/************************************************************************
 *   IRC - Internet Relay Chat, src/m_svscmds.c
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 1, or (at your option)
 *   any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "channel.h"
#include "msg.h"		  /* For TOK_*** and MSG_*** strings  */
#include "hash.h"		  /* For CHANNELHASHSIZE */
#include "h.h"


/*
   **
   ** This file holds the SVS* commands
   ** Commands can be used via RAW
   ** Currently: SVSJOIN, SVSPART, SVSMODE
   **
 */

//Have to define this twice. Sucks eh?
int svs_user_modes[] = {
	UMODE_OPER, 'o',
    UMODE_LOCOP, 'O',
    UMODE_INVISIBLE, 'i',
    UMODE_FAILOP, 'g',
    UMODE_SERVNOTICE, 's',
    UMODE_KILLS, 'k',
    UMODE_SADMIN, 'a',
    UMODE_SROOT, 'n',
    UMODE_NETADMIN, 'N',
    UMODE_NETMANAG, 'M',
	UMODE_TECHADMN, 'L',
	UMODE_HIGHPROT, 'X',
    UMODE_NETFOUND, 'j',
    UMODE_ADMIN, 'A',
    UMODE_CLIENT, 'c',
    UMODE_RCLIENT, 'F',
    UMODE_FLOOD, 'f',
    UMODE_WEBTV, 'w',
    UMODE_HIDE, 'x',
    UMODE_WHOIS, 'y',
#ifdef SEEUSERSTATS
    UMODE_STATS, 't',
#endif
    UMODE_IDENTIFY, 'I',
    UMODE_REGMSGONLY, 'R',
    0, 0
};


/*
 * m_svsmode() added by taz
 * parv[0] - sender
 * parv[1] - username to change mode for
 * parv[2] - modes to change
 * parv[3] - Service Stamp (if mode == d)
 *
 * int show added 1 Oct 2005 by Kei - Shows Mode Change To User
 */
int m_svsmode(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	do_svsmode(cptr, sptr, parc, parv, 0);
}
int m_svs2mode(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	do_svsmode(cptr, sptr, parc, parv, 1);
}
int do_svsmode (aClient *cptr, aClient *sptr, int parc, char *parv[], int show)
{
    int flag;
    int *s;
    char **p, *m;
    aClient *acptr;
    int what, setflags;

	char *xmsg = show ? MSG_SVS2MODE : MSG_SVSMODE;

    if (!IsULine (cptr, sptr))
	return 0;

    what = MODE_ADD;

    if (parc < 3)
	return 0;

    if (!(acptr = find_person (parv[1], NULL)))
	return 0;

    setflags = 0;
    for (s = svs_user_modes; (flag = *s); s += 2)
	if (acptr->umodes & flag)
	    setflags |= flag;
    /*
     * parse mode change string(s)
     */
    for (p = &parv[2]; p && *p; p++)
	for (m = *p; *m; m++)
	    switch (*m) {
	    case '+':
		what = MODE_ADD;
		break;
	    case '-':
		what = MODE_DEL;
		break;
		/* we may not get these,
		 * but they shouldnt be in default
		 */
	    case ' ':
	    case '\n':
	    case '\r':
	    case '\t':
		break;
	    case 'l':
		if (parv[3] && isdigit (*parv[3]))
		    max_global_count = atoi (parv[3]);
		break;
	    case 'd':
		if (parv[3] && isdigit (*parv[3]))
		    acptr->user->servicestamp = atol (parv[3]);
		break;
	    case 'n':
		if (what == MODE_ADD) {
		    acptr->umodes |= UMODE_SROOT;
		}
		else if (what == MODE_DEL) {
		    acptr->umodes &= ~UMODE_SROOT;
		}
		break;
	    case 'j':
                if (what == MODE_ADD) {
                    acptr->umodes |= UMODE_NETFOUND;
                }
                else if (what == MODE_DEL) {
                    acptr->umodes &= ~UMODE_NETFOUND;
                }
                break;
	    case 'N':
		if (what == MODE_ADD) {
		    acptr->umodes |= UMODE_NETADMIN;
		}
		else if (what == MODE_DEL) {
		    acptr->umodes &= ~UMODE_NETADMIN;
		}
		break;
	    case 'M':
		if (what == MODE_ADD) {
		    acptr->umodes |= UMODE_NETMANAG;
		}
		else if (what == MODE_DEL) {
		    acptr->umodes &= ~UMODE_NETMANAG;
		}
		break;
	    case 'I':
		if (what == MODE_ADD) {
		    acptr->umodes |= UMODE_IDENTIFY;
		}
		else if (what == MODE_DEL) {
		    acptr->umodes &= ~UMODE_IDENTIFY;
		}
		break;
	    case 'w':
		if (what == MODE_ADD) {
		    acptr->umodes |= UMODE_WEBTV;
		}
		else if (what == MODE_DEL) {
		    acptr->umodes &= ~UMODE_WEBTV;
		}
		break;
	    default:
		for (s = svs_user_modes; (flag = *s); s += 2)
		    if (*m == (char) (*(s + 1))) {
			if (what == MODE_ADD)
			    acptr->umodes |= flag;
			else
			    acptr->umodes &= ~flag;
			break;
		    }
		break;
	    }

    /* Update mask after SVSMODE -GZ */

    calc_mask(acptr) ;

	if (parc > 3)
	sendto_serv_butone (cptr, ":%s %s %s %s %s",
			    parv[0], xmsg, parv[1], parv[2], parv[3]);
    else
	sendto_serv_butone (cptr, ":%s %s %s %s", parv[0], xmsg, parv[1],
			    parv[2]);

	if (show)
	{
		char buf[BUFSIZE];
		send_umode(NULL, acptr, setflags, ALL_UMODES, buf);
		if (MyClient(acptr) && buf[0] && buf[1])
			sendto_one(acptr, ":%s MODE %s :%s", parv[0], parv[1], buf);
	}

    return 0;
}


/*
   ** m_svsjoin
   **
   ** This function allows an U lined server to force a client to
   ** join a channel.  -- Remmy
   **
   **   parv[0] = sender prefix
   **   parv[1] = nick
   **   parv[2] = channel to join
 */
int m_svsjoin (aClient *cptr, aClient *sptr, int parc, char *parv[])
{
    aClient *acptr;

    if (!IsULine (cptr, sptr))
	return -1;

    /* If this person is online and using this server,
       push them into the channel. */
    if (!hunt_server (cptr, sptr, ":%s SVSJOIN %s %s", 1, parc, parv) !=
	HUNTED_ISME) {
        if ((acptr = find_person (parv[1], NULL)))
            if (MyConnect(acptr))
                m_join (&me, acptr, parc, &parv[1]);
    }

    return 0;
}

/*
   ** m_svspart
   **   parv[0] = sender prefix
   **   parv[1] = channel
 */
int m_svspart (aClient *cptr, aClient *sptr, int parc, char *parv[])
{
    aClient *acptr;

    if (!IsULine (cptr, sptr))
	return -1;

    /* If this person is online and using this server,
       push them out of the channel. */
    if (!hunt_server (cptr, sptr, ":%s SVSPART %s %s", 1, parc, parv) !=
	HUNTED_ISME) {
        if ((acptr = find_person (parv[1], NULL)))
            if (MyConnect(acptr))
                m_part (&me, acptr, parc - 1, &parv[1]);
    }

    return 0;
}

/*
   ** m_svskill
   **   parv[0] = servername
   **   parv[1] = client
   **   parv[2] = kill message
 */
int m_svskill (aClient *cptr, aClient *sptr, int parc, char *parv[])
{
    aClient *acptr;
    char *comment = (parc > 2 && parv[2]) ? parv[2] : "Connection Terminated";

    if (!IsULine (cptr, sptr))
	return -1;

    if (hunt_server (cptr, sptr, ":%s SVSKILL %s :%s", 1, parc, parv) !=
	HUNTED_ISME)
	return 0;

    if (parc < 1 || (!(acptr = find_client (parv[1], NULL))))
	return 0;

    sendto_locfailops ("*** SVSKill: %s", parv[1]);
    return exit_client (acptr, acptr, acptr, comment);
}


